#!/bin/bash
# =============================================================================
# Ansible自动化运维系统 - 依赖包下载脚本
# 功能：下载所有部署所需的依赖包、二进制文件和Python包
# 适用：CentOS 7 离线安装环境
# 作者：Ansible项目组
# 版本：1.0
# =============================================================================

set -e  # 遇到错误立即退出

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 配置变量
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.."
OFFLINE_DIR="${BASE_DIR}/offline-packages"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="${BASE_DIR}/logs/download_${DATE}.log"

# 创建必要目录
mkdir -p "${OFFLINE_DIR}/{rpms,python-packages,binaries,configs}"
mkdir -p "${BASE_DIR}/logs"

# 版本配置
PROMETHEUS_VERSION="2.45.0"
NODE_EXPORTER_VERSION="1.6.1"
GRAFANA_VERSION="10.0.3"
ALERTMANAGER_VERSION="0.25.0"

# 系统信息检测
detect_system() {
    log_info "检测系统信息..."
    
    if [ -f /etc/redhat-release ]; then
        OS="centos"
        VERSION=$(rpm -q --queryformat '%{VERSION}' centos-release 2>/dev/null || echo "7")
        ARCH=$(uname -m)
        log_info "检测到系统: CentOS ${VERSION} (${ARCH})"
    else
        log_error "不支持的操作系统，此脚本仅支持CentOS 7"
        exit 1
    fi
}

# 下载RPM包
download_rpms() {
    log_info "开始下载RPM包..."
    
    # 基础系统包
    local base_packages=(
        "epel-release"
        "python3"
        "python3-pip"
        "python3-setuptools"
        "python3-devel"
        "git"
        "wget"
        "curl"
        "tar"
        "gzip"
        "rsync"
        "openssh-clients"
        "openssh-server"
        "firewalld"
        "systemd"
        "crontabs"
        "logrotate"
    )
    
    # 监控相关包
    local monitoring_packages=(
        "net-tools"
        "htop"
        "iotop"
        "sysstat"
        "lsof"
        "tcpdump"
        "nmap-ncat"
    )
    
    # 安全相关包
    local security_packages=(
        "aide"
        "rkhunter"
        "chkrootkit"
        "fail2ban"
        "audit"
        "auditd"
        "libpwquality"
        "cracklib"
        "cracklib-dicts"
    )
    
    # 数据库相关包
    local database_packages=(
        "mysql"
        "mysql-server"
        "mysql-devel"
        "postgresql"
        "postgresql-server"
        "postgresql-devel"
        "redis"
    )
    
    # Web服务器包
    local web_packages=(
        "nginx"
        "httpd"
        "mod_ssl"
    )
    
    # 合并所有包列表
    local all_packages=("${base_packages[@]}" "${monitoring_packages[@]}" "${security_packages[@]}" "${database_packages[@]}" "${web_packages[@]}")
    
    log_info "下载基础RPM包到 ${OFFLINE_DIR}/rpms/"
    
    # 使用yumdownloader下载包及其依赖
    if ! command -v yumdownloader &> /dev/null; then
        log_warning "yumdownloader未安装，正在安装yum-utils..."
        yum install -y yum-utils
    fi
    
    cd "${OFFLINE_DIR}/rpms"
    
    for package in "${all_packages[@]}"; do
        log_info "下载包: ${package}"
        yumdownloader --resolve --destdir="${OFFLINE_DIR}/rpms" "${package}" 2>/dev/null || {
            log_warning "包 ${package} 下载失败，跳过"
        }
    done
    
    # 创建本地仓库
    if command -v createrepo &> /dev/null; then
        log_info "创建本地YUM仓库..."
        createrepo "${OFFLINE_DIR}/rpms"
    else
        log_warning "createrepo未安装，请手动安装: yum install -y createrepo"
    fi
    
    log_success "RPM包下载完成"
}

# 下载Python包
download_python_packages() {
    log_info "开始下载Python包..."
    
    local python_packages=(
        "flask==2.3.2"
        "requests==2.31.0"
        "pyyaml==6.0"
        "jinja2==3.1.2"
        "ansible==6.7.0"
        "psutil==5.9.5"
        "pymysql==1.1.0"
        "psycopg2-binary==2.9.7"
        "redis==4.6.0"
        "prometheus-client==0.17.1"
        "virtualenv==20.24.2"
        "setuptools==68.0.0"
        "wheel==0.40.0"
        "pip==23.2.1"
    )
    
    log_info "下载Python包到 ${OFFLINE_DIR}/python-packages/"
    
    # 确保pip可用
    if ! command -v pip3 &> /dev/null; then
        log_error "pip3未安装，请先安装python3-pip"
        return 1
    fi
    
    # 升级pip
    pip3 install --upgrade pip
    
    # 下载Python包
    for package in "${python_packages[@]}"; do
        log_info "下载Python包: ${package}"
        pip3 download --dest "${OFFLINE_DIR}/python-packages" "${package}" --no-deps 2>/dev/null || {
            log_warning "Python包 ${package} 下载失败，尝试下载最新版本"
            package_name=$(echo "${package}" | cut -d'=' -f1)
            pip3 download --dest "${OFFLINE_DIR}/python-packages" "${package_name}" --no-deps 2>/dev/null || {
                log_warning "Python包 ${package_name} 下载失败，跳过"
            }
        }
    done
    
    # 下载依赖包
    log_info "下载Python依赖包..."
    for package in "${python_packages[@]}"; do
        package_name=$(echo "${package}" | cut -d'=' -f1)
        pip3 download --dest "${OFFLINE_DIR}/python-packages" "${package_name}" 2>/dev/null || {
            log_warning "${package_name} 依赖包下载失败，跳过"
        }
    done
    
    log_success "Python包下载完成"
}

# 下载二进制文件
download_binaries() {
    log_info "开始下载二进制文件..."
    
    cd "${OFFLINE_DIR}/binaries"
    
    # 下载Prometheus
    log_info "下载Prometheus ${PROMETHEUS_VERSION}..."
    wget -q "https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz" || {
        log_warning "Prometheus下载失败"
    }
    
    # 下载Node Exporter
    log_info "下载Node Exporter ${NODE_EXPORTER_VERSION}..."
    wget -q "https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz" || {
        log_warning "Node Exporter下载失败"
    }
    
    # 下载Alertmanager
    log_info "下载Alertmanager ${ALERTMANAGER_VERSION}..."
    wget -q "https://github.com/prometheus/alertmanager/releases/download/v${ALERTMANAGER_VERSION}/alertmanager-${ALERTMANAGER_VERSION}.linux-amd64.tar.gz" || {
        log_warning "Alertmanager下载失败"
    }
    
    # 下载Grafana
    log_info "下载Grafana ${GRAFANA_VERSION}..."
    wget -q "https://dl.grafana.com/enterprise/release/grafana-enterprise-${GRAFANA_VERSION}.linux-amd64.tar.gz" || {
        log_warning "Grafana下载失败，尝试下载OSS版本"
        wget -q "https://dl.grafana.com/oss/release/grafana-${GRAFANA_VERSION}.linux-amd64.tar.gz" || {
            log_warning "Grafana OSS版本下载失败"
        }
    }
    
    log_success "二进制文件下载完成"
}

# 下载配置文件和脚本
download_configs() {
    log_info "准备配置文件和脚本..."
    
    # 复制项目配置文件
    cp -r "${BASE_DIR}/group_vars" "${OFFLINE_DIR}/configs/" 2>/dev/null || true
    cp -r "${BASE_DIR}/roles" "${OFFLINE_DIR}/configs/" 2>/dev/null || true
    cp "${BASE_DIR}/ansible.cfg" "${OFFLINE_DIR}/configs/" 2>/dev/null || true
    
    # 创建离线安装说明
    cat > "${OFFLINE_DIR}/README-OFFLINE.md" << 'EOF'
# 离线安装包使用说明

## 目录结构
```
offline-packages/
├── rpms/                    # RPM包及本地仓库
├── python-packages/         # Python包
├── binaries/               # 二进制文件
├── configs/                # 配置文件
└── README-OFFLINE.md       # 本说明文件
```

## 安装步骤

1. 将整个offline-packages目录复制到目标服务器
2. 运行离线安装脚本：`./install-offline.sh`
3. 按照提示完成安装配置

## 注意事项

- 确保目标系统为CentOS 7
- 需要root权限执行安装
- 安装前请备份重要数据
EOF
    
    log_success "配置文件准备完成"
}

# 生成校验文件
generate_checksums() {
    log_info "生成文件校验和..."
    
    cd "${OFFLINE_DIR}"
    
    # 生成MD5校验文件
    find . -type f -name "*.rpm" -o -name "*.tar.gz" -o -name "*.whl" | xargs md5sum > checksums.md5
    
    # 生成SHA256校验文件
    find . -type f -name "*.rpm" -o -name "*.tar.gz" -o -name "*.whl" | xargs sha256sum > checksums.sha256
    
    log_success "校验文件生成完成"
}

# 打包离线安装包
package_offline() {
    log_info "打包离线安装包..."
    
    cd "${BASE_DIR}"
    
    # 创建压缩包
    tar -czf "ansible-offline-packages-${DATE}.tar.gz" offline-packages/
    
    # 显示包大小
    local size=$(du -h "ansible-offline-packages-${DATE}.tar.gz" | cut -f1)
    log_success "离线安装包创建完成: ansible-offline-packages-${DATE}.tar.gz (${size})"
}

# 清理临时文件
cleanup() {
    log_info "清理临时文件..."
    # 这里可以添加清理逻辑
    log_success "清理完成"
}

# 显示使用帮助
show_help() {
    cat << EOF
使用方法: $0 [选项]

选项:
  -h, --help          显示此帮助信息
  -a, --all           下载所有依赖包（默认）
  -r, --rpms          仅下载RPM包
  -p, --python        仅下载Python包
  -b, --binaries      仅下载二进制文件
  -c, --configs       仅准备配置文件
  --no-package        不创建压缩包
  --clean             清理已下载的文件

示例:
  $0                  # 下载所有依赖包并打包
  $0 -r               # 仅下载RPM包
  $0 --no-package     # 下载但不打包
  $0 --clean          # 清理下载文件
EOF
}

# 主函数
main() {
    local download_all=true
    local download_rpms=false
    local download_python=false
    local download_binaries=false
    local download_configs=false
    local create_package=true
    local clean_files=false
    
    # 解析命令行参数
    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help)
                show_help
                exit 0
                ;;
            -a|--all)
                download_all=true
                shift
                ;;
            -r|--rpms)
                download_all=false
                download_rpms=true
                shift
                ;;
            -p|--python)
                download_all=false
                download_python=true
                shift
                ;;
            -b|--binaries)
                download_all=false
                download_binaries=true
                shift
                ;;
            -c|--configs)
                download_all=false
                download_configs=true
                shift
                ;;
            --no-package)
                create_package=false
                shift
                ;;
            --clean)
                clean_files=true
                shift
                ;;
            *)
                log_error "未知选项: $1"
                show_help
                exit 1
                ;;
        esac
    done
    
    # 清理文件
    if [[ "$clean_files" == "true" ]]; then
        log_info "清理下载文件..."
        rm -rf "${OFFLINE_DIR}"
        rm -f "${BASE_DIR}/ansible-offline-packages-"*.tar.gz
        log_success "清理完成"
        exit 0
    fi
    
    # 开始下载流程
    log_info "开始下载Ansible部署依赖包..."
    log_info "目标目录: ${OFFLINE_DIR}"
    
    detect_system
    
    # 根据参数执行相应的下载任务
    if [[ "$download_all" == "true" ]]; then
        download_rpms
        download_python_packages
        download_binaries
        download_configs
    else
        [[ "$download_rpms" == "true" ]] && download_rpms
        [[ "$download_python" == "true" ]] && download_python_packages
        [[ "$download_binaries" == "true" ]] && download_binaries
        [[ "$download_configs" == "true" ]] && download_configs
    fi
    
    generate_checksums
    
    if [[ "$create_package" == "true" ]]; then
        package_offline
    fi
    
    log_success "所有下载任务完成！"
    log_info "离线安装包位置: ${OFFLINE_DIR}"
    
    if [[ "$create_package" == "true" ]]; then
        log_info "压缩包位置: ${BASE_DIR}/ansible-offline-packages-${DATE}.tar.gz"
    fi
}

# 脚本入口
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi